package com.vcc.service.impl;

import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryChain;
import com.mybatisflex.core.update.UpdateChain;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.vcc.core.exception.ProgramException;
import com.vcc.core.util.RegexUtil;
import com.vcc.data.entity.CardGroup;
import com.vcc.data.entity.Role;
import com.vcc.data.entity.User;
import com.vcc.data.mapper.CardGroupMapper;
import com.vcc.service.client.dto.cardGroup.UpdateCardGroupDto;
import com.vcc.service.client.vo.cardGroup.CardGroupVo;
import com.vcc.service.service.CardGroupService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.List;

import static com.vcc.data.entity.table.CardGroupTableDef.CARD_GROUP;
import static com.vcc.data.entity.table.TransferOrderTableDef.TRANSFER_ORDER;
import static com.vcc.data.entity.table.UserCardTableDef.USER_CARD;
import static com.vcc.data.entity.table.UserTableDef.USER;

@Service
public class CardGroupServiceImpl extends ServiceImpl<CardGroupMapper, CardGroup> implements CardGroupService {


    @Override
    public CardGroup initDefaultGroup(Long userId) {
        CardGroup cardGroup = new CardGroup();
        cardGroup.setUserId(userId);
        cardGroup.setName("默认分组");
        cardGroup.setDescription("系统默认分组");
        cardGroup.setSort(0);
        cardGroup.setStatus(0);
        cardGroup.setHasDefault(true);
        save(cardGroup);
        return cardGroup;
    }

    @Override
    public Boolean existsByNameAndUserId(Long userId, String name) {
        return queryChain().eq(CardGroup::getUserId, userId).eq(CardGroup::getName, name).exists();
    }


    @Override
    public Page<CardGroupVo> clientPaging(Integer pageNumber, Integer pageSize, Role role, Long targetUserId, Long userId, String name, Integer status) {
        QueryChain<CardGroup> queryChain = queryChain()
                .select(CARD_GROUP.ALL_COLUMNS)
                .select(" (SELECT COUNT(*) FROM `vcc_user_card` WHERE `card_group_id` = `vcc_card_group`.`id`) AS cardCount")
                .select(USER.EMAIL.as("account"))
                .leftJoin(USER).on(USER.ID.eq(CARD_GROUP.USER_ID))
                .where(CARD_GROUP.NAME.like(name, StringUtils::isNotBlank))
                .where(CARD_GROUP.STATUS.eq(status, status != null))
                .orderBy(CARD_GROUP.SORT.asc());
        if (role.getHasAllData()) {
            queryChain.where(
                    USER.PARENT_ID.eq(userId).or(USER.ID.eq(userId))
            );
            if (RegexUtil.checkObjectIsNotNull(targetUserId)) {
                queryChain.where(CARD_GROUP.USER_ID.eq(targetUserId));
            }
        } else {
            queryChain.where(CARD_GROUP.USER_ID.eq(userId));
        }
        return pageAs(
                Page.of(pageNumber == null ? 1 : pageNumber, pageSize == null ? 20 : pageSize),
                queryChain,
                CardGroupVo.class
        );
    }

    @Override
    public Boolean update(UpdateCardGroupDto updateCardGroupDto, Long userId) {
        CardGroup cardGroup = getByIdOpt(updateCardGroupDto.getId()).orElseThrow(() -> new ProgramException("未找到该卡组"));
        if (cardGroup.getHasDefault()){
            throw new ProgramException("默认卡组不允许修改");
        }
        UpdateChain<CardGroup> cardGroupUpdateChain = updateChain();
        if (StringUtils.isNotBlank(updateCardGroupDto.getName()) && !cardGroup.getName().equals(updateCardGroupDto.getName())) {
            if (existsByNameAndUserId(userId, updateCardGroupDto.getName())) {
                throw new ProgramException("该卡组名称已存在");
            }
            cardGroupUpdateChain.set(CardGroup::getName, updateCardGroupDto.getName());
        }
        if (StringUtils.isNotBlank(updateCardGroupDto.getDescription()) && !updateCardGroupDto.getDescription().equals(cardGroup.getDescription())) {
            cardGroupUpdateChain.set(CardGroup::getDescription, updateCardGroupDto.getDescription());
        }
        if (updateCardGroupDto.getSort() != null && updateCardGroupDto.getSort() >= 0 && !cardGroup.getSort().equals(updateCardGroupDto.getSort())) {
            cardGroupUpdateChain.set(CardGroup::getSort, updateCardGroupDto.getSort());
        }
        if (updateCardGroupDto.getStatus() != null && !cardGroup.getStatus().equals(updateCardGroupDto.getStatus())) {
            cardGroupUpdateChain.set(CardGroup::getStatus, updateCardGroupDto.getStatus());
        }
        cardGroupUpdateChain.eq(CardGroup::getId, updateCardGroupDto.getId());
        return cardGroupUpdateChain.update();
    }


    @Override
    public List<CardGroupVo> listByName(Long userId, Role role, String name) {
        QueryChain<CardGroup> queryChain = queryChain()
                .select(CARD_GROUP.ALL_COLUMNS)
                .select(" (SELECT COUNT(*) FROM `vcc_user_card` WHERE `card_group_id` = `vcc_card_group`.`id`) AS cardCount")
                .where(CARD_GROUP.NAME.like(name, StringUtils::isNotBlank))
                .where(CARD_GROUP.STATUS.eq(0))
                .orderBy(CARD_GROUP.SORT.asc());
        if (role.getHasAllData()) {
            queryChain.leftJoin(USER).on(USER.ID.eq(CARD_GROUP.USER_ID)).where(
                    USER.PARENT_ID.eq(userId).or(USER.ID.eq(userId))
            );
        } else {
            queryChain.where(CARD_GROUP.USER_ID.eq(userId));
        }
        return listAs(queryChain, CardGroupVo.class);
    }

    @Override
    public List<CardGroupVo> listByName(Long userId, Role role, String name, Long targetUserId) {
        QueryChain<CardGroup> queryChain = queryChain()
                .select(CARD_GROUP.ALL_COLUMNS)
                .select(" (SELECT COUNT(*) FROM `vcc_user_card` WHERE `card_group_id` = `vcc_card_group`.`id`) AS cardCount")
                .where(CARD_GROUP.NAME.like(name, StringUtils::isNotBlank))
                .where(CARD_GROUP.STATUS.eq(0))
                .orderBy(CARD_GROUP.SORT.asc());
        if (role.getHasAllData()) {
            queryChain.leftJoin(USER).on(USER.ID.eq(CARD_GROUP.USER_ID)).where(
                    USER.PARENT_ID.eq(userId).or(USER.ID.eq(userId))
            );
            queryChain.where(CARD_GROUP.USER_ID.eq(targetUserId));
        } else {
            queryChain.where(CARD_GROUP.USER_ID.eq(userId));
        }
        return listAs(queryChain, CardGroupVo.class);
    }

}
